package com.example;

import java.math.BigDecimal;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class SimpleBank implements Bank{

    private ConcurrentMap<Integer, Account> data = new ConcurrentHashMap<>();

    @Override
    public BigDecimal getTheBalance(Integer accountId) throws AccountNotExistException {
        Account account = data.get(accountId);
        if(account == null){
            throw new AccountNotExistException(accountId + " not exists.");
        }
        return account.getTheBalance();
    }

    @Override
    public void store(Integer accountId, BigDecimal money) {
        Account account = data.get(accountId);
        if(account == null){
            account = new SimpleAccount();
            data.put(accountId, account);
        }
        account.store(money);

    }

    @Override
    public void withdrawMoney(Integer accountId, BigDecimal money) throws InsufficientBalanceException, AccountNotExistException {
        Account account = data.get(accountId);
        if(account != null){
            account.withdrawMoney(money);
        }else {
            throw new AccountNotExistException(accountId + "not exists.");
        }
    }
}

class SimpleAccount implements Account{

    private volatile BigDecimal balance = new BigDecimal(0);
    private ReentrantLock reentrantLock = new ReentrantLock();

    @Override
    public BigDecimal getTheBalance() {
        return balance;
    }

    @Override
    public void store(BigDecimal money) {
        reentrantLock.lock();
        try{
            balance = balance.add(money);
        }finally {
            reentrantLock.unlock();
        }
    }

    @Override
    public void withdrawMoney(BigDecimal money) throws InsufficientBalanceException {
        reentrantLock.lock();
        try {
            if(balance.compareTo(money) < 0){
                throw new InsufficientBalanceException("balance:" + balance + ", withdraw:" + money);
            }
            balance = balance.subtract(money);
        }finally {
            reentrantLock.unlock();
        }
    }
}